/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2008 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author:                                                              |
  +----------------------------------------------------------------------+
*/

/* $Id: header 252479 2008-02-07 19:39:50Z iliaa $ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "php_main.h"
#include "php_theme.h"
#include "ext/standard/info.h"
#include "SAPI.h"

#include <zend_interfaces.h>

/* If you declare any globals in php_theme.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(theme)
*/

/* True global resources - no need for thread safety here */
static char *ht_rdir = "";
static zend_class_entry* theme_class_entry;
static zend_object_handlers theme_object_handlers;

/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO(arginfo_theme_assign, 0)
	ZEND_ARG_INFO(0, skey)
	ZEND_ARG_INFO(0, sval)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_theme_exists, 0)
	ZEND_ARG_INFO(0, stpl)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_theme_display, 0)
	ZEND_ARG_INFO(0, stpl)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_theme_obtain, 0)
	ZEND_ARG_INFO(0, skey)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_theme_version, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_theme_construct, 0)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_theme_destruct, 0)
ZEND_END_ARG_INFO()
/* }}} */

/* {{{ theme_functions[]
 *
 * Every user visible function must have an entry in theme_functions[].
 */
const zend_function_entry theme_functions[] = {
	PHP_ME(theme, assign, arginfo_theme_assign, ZEND_ACC_PUBLIC)
	PHP_ME(theme, exists, arginfo_theme_exists, ZEND_ACC_PUBLIC)
	PHP_ME(theme, display, arginfo_theme_display, ZEND_ACC_PUBLIC)
	PHP_ME(theme, obtain, arginfo_theme_obtain, ZEND_ACC_PUBLIC)
	PHP_ME(theme, version, arginfo_theme_version, ZEND_ACC_PUBLIC)
	PHP_ME(theme, __construct, arginfo_theme_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
	PHP_ME(theme, __destruct, arginfo_theme_destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
	//PHP_FE(theme, NULL)
	{NULL, NULL, NULL}	/* Must be the last line in theme_functions[] */
};
/* }}} */

/* {{{ theme_module_entry
 */
zend_module_entry theme_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
	STANDARD_MODULE_HEADER,
#endif
	"theme",
	theme_functions,
	PHP_MINIT(theme),
	PHP_MSHUTDOWN(theme),
	PHP_RINIT(theme),		/* Replace with NULL if there's nothing to do at request start */
	PHP_RSHUTDOWN(theme),		/* Replace with NULL if there's nothing to do at request end */
	PHP_MINFO(theme),
#if ZEND_MODULE_API_NO >= 20010901
	PHP_THEME_VERSION, /* Replace with version number for your extension */
#endif
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_THEME
ZEND_GET_MODULE(theme)
#endif

/* {{{ PHP_INI
 */
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
    STD_PHP_INI_ENTRY("theme.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_theme_globals, theme_globals)
    STD_PHP_INI_ENTRY("theme.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_theme_globals, theme_globals)
PHP_INI_END()
*/
/* }}} */

/* {{{ php_theme_init_globals
 */
/* Uncomment this function if you have INI entries
static void php_theme_init_globals(zend_theme_globals *theme_globals)
{
	theme_globals->global_value = 0;
	theme_globals->global_string = NULL;
}
*/
/* }}} */

/* {{{ PHP_MINIT_FUNCTION
 */
PHP_MINIT_FUNCTION(theme)
{
	/* If you have INI entries, uncomment these lines 
	REGISTER_INI_ENTRIES();char md5str[33];
	PHP_MD5_CTX context;
	unsigned char digest[16];
	*/
	zend_class_entry class_entry;
	INIT_CLASS_ENTRY(class_entry, "theme", theme_functions);
	theme_class_entry = zend_register_internal_class(&class_entry TSRMLS_CC);

	zend_declare_property_string(theme_class_entry, ZEND_STRL("dir"), "", ZEND_ACC_PUBLIC TSRMLS_CC);
	zend_declare_property_string(theme_class_entry, ZEND_STRL("tpl"), "", ZEND_ACC_PRIVATE TSRMLS_CC);
	zend_declare_property_null(theme_class_entry, ZEND_STRL("dat"), ZEND_ACC_PRIVATE TSRMLS_CC);
 
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(theme)
{
	/* uncomment this line if you have INI entries
	UNREGISTER_INI_ENTRIES();
	*/
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request start */
/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(theme)
{
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request end */
/* {{{ PHP_RSHUTDOWN_FUNCTION
 */
PHP_RSHUTDOWN_FUNCTION(theme)
{
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(theme)
{
	php_info_print_table_start();
	php_info_print_table_row(2, "Theme Support", "enabled");
	php_info_print_table_row(2, "Theme Version", PHP_THEME_VERSION);
	php_info_print_table_end();

	/* Remove comments if you have entries in php.ini
	DISPLAY_INI_ENTRIES();
	*/
}
/* }}} */


/* Remove the following function when you have succesfully modified config.m4
   so that your module can be compiled into PHP, it exists only for testing
   purposes. */

PHP_METHOD(theme, assign) /* {{{ */
{
	Bucket *p;
	zval *object, *zdat, *zkey, *valu = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &zkey, &valu) == FAILURE) {
		 WRONG_PARAM_COUNT;
	}

	object = getThis();
	zdat = zend_read_property(theme_class_entry, object, ZEND_STRL("dat"), 0 TSRMLS_CC);
	if (Z_TYPE_P(zdat) != IS_ARRAY) {
		MAKE_STD_ZVAL(zdat);
		array_init(zdat);
	}

	if (Z_TYPE_P(zkey) == IS_ARRAY) {

		for (p = Z_ARRVAL_P(zkey)->pListHead; p != NULL; p = p->pListNext) {
			Z_ADDREF_PP((zval**)p->pData);

			if (p->nKeyLength == 0) {
				zend_hash_index_update(Z_ARRVAL_P(zdat), p->h, p->pData, sizeof(zval*), NULL);
			} else {
				zend_hash_quick_update(Z_ARRVAL_P(zdat), p->arKey, p->nKeyLength, p->h, p->pData, sizeof(zval*), NULL);
			}
		}
		zend_update_property(theme_class_entry, object, ZEND_STRL("dat"), zdat TSRMLS_CC);
		RETURN_TRUE;
	}

	zval_addref_p(valu);
	convert_to_string(zkey);
	if (zend_hash_update(Z_ARRVAL_P(zdat),Z_STRVAL_P(zkey), Z_STRLEN_P(zkey) + 1, (void**)&valu, sizeof(zval*), NULL) != FAILURE) {
		zend_update_property(theme_class_entry, object, ZEND_STRL("dat"), zdat TSRMLS_CC);
		RETURN_TRUE;
	}

	RETURN_FALSE;
}
/* }}} */

PHP_METHOD(theme, exists) /* {{{ */
{
	zval *object, *zdir;
	char *path, *stpl = NULL;
	int stpl_len = 0;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &stpl, &stpl_len) == FAILURE) {
		 WRONG_PARAM_COUNT;
	}

	object = getThis();
	zdir = zend_read_property(theme_class_entry, object, ZEND_STRL("dir"), 0 TSRMLS_CC);
	spprintf(&path, MAXPATHLEN, "%s/%s.tpl.php", Z_STRVAL_P(zdir), stpl);
	zend_update_property_string(theme_class_entry, object, ZEND_STRL("tpl"), path TSRMLS_CC);
	if (VCWD_ACCESS(path, F_OK) != 0) {
		RETURN_FALSE;
	}

	RETURN_TRUE;
}
/* }}} */

PHP_METHOD(theme, display) /* {{{ */
{
	char *path, *stpl = NULL;
	int stpl_len = 0;
	zval *object, *zdir, *zdat;
	zend_file_handle handle;

	zval **entry;
	HashPosition hpos;
	ulong num_key;
	char *key_val;
	uint key_len;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &stpl, &stpl_len) == FAILURE) {
		 WRONG_PARAM_COUNT;
	}

	object = getThis();
	zdir = zend_read_property(theme_class_entry, object, ZEND_STRL("dir"), 0 TSRMLS_CC);
	spprintf(&path, MAXPATHLEN, "%s/%s.tpl.php", Z_STRVAL_P(zdir), stpl);
	zend_update_property_string(theme_class_entry, object, ZEND_STRL("dir"), path TSRMLS_CC);
	if (VCWD_ACCESS(path, F_OK) != 0) {
		zend_error(E_ERROR, "Cannot find template file: %s", path);
	}

#ifdef PHP_WIN32
	if (zend_stream_open(path, &handle, (void ***)tsrm_ls) == SUCCESS) {
#else
	if (zend_stream_open(path, &handle TSRMLS_DC) == SUCCESS) {
#endif
		ALLOC_HASHTABLE(EG(active_symbol_table));
		zend_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0);

		zdat = zend_read_property(theme_class_entry, object, ZEND_STRL("dat"), 0 TSRMLS_CC);
		if (Z_TYPE_P(zdat) == IS_ARRAY) {

			zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(zdat), &hpos);
			while (zend_hash_get_current_data_ex(Z_ARRVAL_P(zdat), (void **)&entry, &hpos) == SUCCESS) {
				zval_add_ref(entry);

				switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(zdat), &key_val, &key_len, &num_key, 0, &hpos)) {
					case HASH_KEY_IS_LONG:
						zend_hash_index_update(EG(active_symbol_table), num_key, (void **) entry, sizeof(zval *), NULL);
						break;
					case HASH_KEY_IS_STRING:
						zend_hash_update(EG(active_symbol_table), key_val, key_len, (void **) entry, sizeof(zval *), NULL);
						break;
				}
				zend_hash_move_forward_ex(Z_ARRVAL_P(zdat), &hpos);
			}
		}

#ifdef PHP_WIN32
		php_execute_script(&handle, (void ***)tsrm_ls);
#else
		php_execute_script(&handle TSRMLS_DC);
#endif
		zend_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0);

		return;
	}

	zend_error(E_ERROR, "Cannot find template file: %s", path);
}
/* }}} */

PHP_METHOD(theme, obtain) /* {{{ */
{
	zval *zdat, **val;
	char *skey = NULL;
	uint skey_len = 0;
	
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &skey, &skey_len) == FAILURE) {
		 WRONG_PARAM_COUNT;
	}
	
	zdat = zend_read_property(theme_class_entry, getThis(), ZEND_STRL("dat"), 0 TSRMLS_CC);
	zend_hash_internal_pointer_reset(Z_ARRVAL_P(zdat));
	if ((Z_TYPE_P(zdat) == IS_ARRAY) && (SUCCESS == zend_hash_find(Z_ARRVAL_P(zdat), skey, skey_len+1, (void **)&val))){
		RETVAL_ZVAL(*val, 1, 0);
		return;
		
	}
	RETURN_FALSE;

}
/* }}} */

PHP_METHOD(theme, version) /* {{{ */
{
	RETURN_STRING(PHP_THEME_VERSION, 1);
}
/* }}} */

PHP_METHOD(theme, __construct) /* {{{ */
{
	zval *zdat, *object;

	if (ZEND_NUM_ARGS() != 0) {
		WRONG_PARAM_COUNT;
	}

	// update propertys
	MAKE_STD_ZVAL(zdat);
	array_init(zdat);

	object = getThis();
	zend_update_property_string(theme_class_entry, object, ZEND_STRL("dir"), "themes/default" TSRMLS_CC);
	zend_update_property_string(theme_class_entry, object, ZEND_STRL("tpl"), "" TSRMLS_CC);
	zend_update_property(theme_class_entry, object, ZEND_STRL("dat"), zdat TSRMLS_CC);

}
/* }}} */

PHP_METHOD(theme, __destruct) /* {{{ */
{

}
/* }}} */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
